#include <math.h>

#include "../../../../WizCore/Include/Base/WizBaseTemplateUtils.hpp"

#include "../../Include/Base/Trigonometry/WizAlgebraTrigonometryTable.hpp"
#include "../../Include/Base/Trigonometry/WizAlgebraTrigonometry.hpp"
#include "../../Include/Utils/WizAlgebraUtilsMisc.hpp"

namespace Wiz
{
    namespace Trigonometry
    {
        //////////////////////////////////////////////////////////////////////////
        namespace Table
        {
            Type::Type()
            {
                ::Wiz::UInt::Type i;
                ::Wiz::Real::Type ang, val;

                for(i = 0; i < this->eTabSize; i++)
                {
                    ang = IndexToAngle(i);      
                    val = IndexToValue(i);
                    /// 
                    this->m_SinTab[i]  = ::sin(ang);
                    this->m_CosTab[i]  = ::cos(ang);
                    this->m_ASinTab[i] = ::asin(val);
                    this->m_ACosTab[i] = ::acos(val);
                    this->m_TanTab[i]  = ::tan(ang);
                }
            }

            /// [-pi, pi]
            ::Wiz::Real::Type Type::IndexToAngle(::Wiz::Int::In i) const
            {
                WIZ_ASSERT(i >= 0 && i < this->eTabSize);

                /// return i * ::Wiz::PITwo / this->eTabSize - ::Wiz::PI;
                return ::Wiz::ConvertRange<::Wiz::Real::Type>(
                    ::Wiz::Cast::Static<::Wiz::Real::Type>(i),
                    0,          this->eTabSize,
                    -::Wiz::PI, ::Wiz::PI
                    );
            }

            /// [ -1, 1]
            ::Wiz::Real::Type Type::IndexToValue(::Wiz::Int::In i) const
            {
                WIZ_ASSERT(i >= 0 && i < this->eTabSize);

                /// return i * 2.0f           / this->eTabSize - 1.0f;
                return ::Wiz::ConvertRange<::Wiz::Real::Type>(
                    ::Wiz::Cast::Static<::Wiz::Real::Type>(i),
                    0,          this->eTabSize,
                    -1,         1
                    );
            }

            ::Wiz::Int::Type  Type::AngleToIndex(::Wiz::Real::In Ang) const
            {
                ::Wiz::Real::TypeConst Idx =
                    ::Wiz::ConvertRange<::Wiz::Real::Type>(
                        ::Wiz::Fmod(Ang, ::Wiz::PI),
                        -::Wiz::PI, ::Wiz::PI,
                        0,          this->eTabSize
                    );
                
                return ::Wiz::Round(Idx);
            }
            ::Wiz::Int::Type  Type::ValueToIndex(::Wiz::Real::In Val) const
            {
                ::Wiz::Real::TypeConst Idx =
                    ::Wiz::ConvertRange<::Wiz::Real::Type>(
                        ::Wiz::Clamp(Val, -1.0f, 1.0f),
                        -1, 1,
                        0,  this->eTabSize
                    );

                return ::Wiz::Round(Idx);
            }
        } /// end of namespace Table
        //////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////////
        Type::Type()
        {
            m_TablePtr = new ::Wiz::Trigonometry::Table::Type();
            if (::Wiz::NotValidPtr(m_TablePtr))
            {
                ::Wiz::Exception::Throw(::Wiz::Exception::BadAlloc());
            }
        }

        Type::~Type()
        {
            if (::Wiz::IsValidPtr(m_TablePtr))
            {
                delete m_TablePtr;
                m_TablePtr = WIZ_NULLPTR;
            }
        }
        //////////////////////////////////////////////////////////////////////////
    } /// end of namespace Trigonometry
} /// end of namespace Wiz

